﻿using System;
using DynamicMocker;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DynamicMockerTests
{
	/// <summary>
	///This is a test class for MockTest and is intended
	///to contain all MockTest Unit Tests
	///</summary>
	[TestClass]
	public class MockTest
	{
		/// <summary>
		///A test for Mock Constructor
		///</summary>
		[TestMethod]
		public void MockConstructorTest()
		{
			var target = new Mock<TestClass>();
			Assert.IsNotNull(target);
		}

		[TestMethod]
		public void MockObjectTest()
		{
			var target = new Mock<TestClass>();
			Assert.IsNotNull(target.Object);
		}

		[TestMethod]
		public void MockCallingOriginalMethodTest()
		{
			var target = new Mock<TestClass>();
			Assert.AreEqual(2, target.Object.TestMethod(1));
		}

		[TestMethod]
		public void MockCallingFakeMethodTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod(5))
				.Returns((int value) => value*10);

			Assert.AreEqual(40, target.Object.TestMethod(4));
		}

		[TestMethod]
		public void MockCallingStaticFakeMethodTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => TestClass.TestStatic(5))
				.Returns((double value) => value*10);

			Assert.AreEqual(40, target.Object.TestStatic(4));
		}

		[TestMethod]
		public void MockCallingOriginalMethodWithTwoArgumentsTest()
		{
			var target = new Mock<TestClass>();
			Assert.AreEqual("string: This is a test string, int: 4", target.Object.TestMethod2(4, "This is a test string"));
		}

		[TestMethod]
		public void MockCallingFakeMethodWithTwoArgumentsTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod2(5, "Test string"))
				.Returns((int intVal, string stringVal) => string.Format("This is a test! {0}, {1}", intVal, stringVal));

			Assert.AreEqual("This is a test! 4, This is a test string", target.Object.TestMethod2(4, "This is a test string"));
		}

		[TestMethod]
		public void MockCallingFakeMethodWithThreeArgumentsTest()
		{
			var target = new Mock<TestClass>();

			var testDate = DateTime.Now;
			target.Setup(testClass => testClass.TestMethod_3(5, "Test string", testDate))
				.Returns((int intVal, string stringVal, DateTime dt) => true);

			Assert.AreEqual(true, target.Object.TestMethod_3(4, "This is a test string", testDate));
		}

		[TestMethod]
		public void MockCallingFakeMethodWhichNotReturnsValueTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod3(5))
				.Returns((int value) => Console.Write("Method without return values is called. Argument: " + value));

			target.Object.TestMethod3(5);
			target.Verify();
		}

		[TestMethod]
		public void MockCallingFakeMethodWithCheckingArgumentsTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod3(It.IsAny<int>()))
				.Returns((int value) => Console.Write("Method without return values is called. Argument: " + value));

			target.Object.TestMethod3(5);
			target.Verify();
		}

		[TestMethod]
		public void MockCallingFakeMethodWithCheckingArgumentTypeShouldThrowExceptionIfTypeIncorrectTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod3(It.IsAny<int>()))
				.Returns((int value) => Console.Write("Method without return values is called. Argument: " + value));
			
			try
			{
				target.Object.TestMethod3(5.3);
				Assert.Fail("IsAny<T> method incorrect!");
			}
			catch
			{
			}
			target.Verify();

		}	

		[TestMethod]
		public void MockCallingFakeMethodWithCheckingArgumentValueTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod3(It.IsEqualTo(5)))
				.Returns((int value) => Console.Write("Method without return values is called. Argument: " + value));

			target.Object.TestMethod3(5);
			target.Verify();
		}

		[TestMethod]
		public void MockCallingFakeMethodWithCheckingArgumentValueShouldThrowExceptionIfValueDifferentTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod3(It.IsEqualTo(5)))
				.Returns((int value) => Console.Write("Method without return values is called. Argument: " + value));
			try
			{
				target.Object.TestMethod3(3);
				Assert.Fail("IsEqualTo<T> method incorrect!");
			}
			catch
			{
			}
			target.Verify();
		}

		[TestMethod]
		public void MockCallingFakeMethodWithRegexCheckingArgumentValueTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod2(0, It.IsMatchTo("test")))
				.Returns((int value, string svalue) => "");

			Assert.AreEqual("", target.Object.TestMethod2(0, "test"));
		}

		[TestMethod]
		public void MockCallingFakeMethodWithRegexCheckingArgumentValueShouldThrowExceptionIfValueDifferentTest()
		{
			var target = new Mock<TestClass>();

			target.Setup(testClass => testClass.TestMethod2(0, It.IsMatchTo("test")))
				.Returns((int value, string svalue) => "");

			try
			{
				Assert.AreEqual("", target.Object.TestMethod2(0, "error"));
				Assert.Fail("IsMatchTo<T> method incorrect!");
			}
			catch
			{
			}
			target.Verify();
		}
	}
}